home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c++-part2 / 14289 < prev    next >
Encoding:
Text File  |  1996-08-05  |  15.7 KB  |  337 lines

  1. Newsgroups: comp.lang.ada,comp.lang.c++
  2. Path: in2.uu.net!world!bobduff
  3. From: bobduff@world.std.com (Robert A Duff)
  4. Subject: Re: some questions re. Ada/GNAT from a C++/GCC user
  5. Message-ID: <Dp1oAw.7Cz@world.std.com>
  6. Bcc: bobduff
  7. Organization: The World Public Access UNIX, Brookline, MA
  8. References: <wnewmanDoxrCp.DKv@netcom.com>
  9. Date: Fri, 29 Mar 1996 19:47:20 GMT
  10.  
  11. In article <wnewmanDoxrCp.DKv@netcom.com>,
  12. Bill Newman <wnewman@netcom.com> wrote:
  13. >...  (I hope against hope that
  14. > the tone of the answers will resemble the cross-language comparisons
  15. > in _Ada as a Second Language_ more closely than it resembles the
  16. > recent C++/Ada flamewar.)
  17.  
  18. ;-)
  19.  
  20. Did you notice the recent Eiffel/Ada flamewar?  It was much more
  21. reasonable -- not even a flamewar, really, but a technical argument.
  22. It *is* possible!
  23.  
  24. > Does GNAT completely implement generics as defined in the standard?
  25. > (I ask because I have heard that no compiler, G++ otherwise, has yet
  26. > implemented C++ templates completely, and the G++ implementation
  27. > caused me lots of hassles before 2.7.x, and still causes some hassles
  28. > now.)
  29. > I *assume* that GNAT supports exceptions completely since they're an integral
  30. > part of the language and I didn't see any disclaimers, but since AFAIK G++
  31. > doesn't do them very well, I'd like to double-check: how well does
  32. > GNAT do exceptions?
  33.  
  34. Generics and exceptions are both standard parts of Ada, so anything that
  35. calls itself an Ada compiler implements them.  Furthermore, these
  36. features have been around since Ada 83 (although a few bells and
  37. whistles were added in Ada 95).  Any compiler can have bugs, of course.
  38. But the situation with C++, where templates and exceptions are pretty
  39. new, and not officially standardized, isn't true of Ada.
  40.  
  41. > I didn't notice anything about garbage collection in the GNAT docs, so
  42. > I assume it doesn't support it.  Will GNAT support GC in the
  43. > foreseeable future?
  44.  
  45. GNAT does not support GC.  I believe somebody is working on adding GC to
  46. GNAT.  Also, the Intermetrics Ada compiler supports GC.
  47.  
  48. > How well does GDB work with GNAT output?
  49.  
  50. I've found it to be somewhat painful.  However, it does work, and the
  51. Ada support is being improved.
  52.  
  53. >...Is it possible to get GDB to
  54. > interactively call arbitrary procedures/functions from GNAT-generated
  55. > code?
  56.  
  57. Yes, I do that a lot.
  58.  
  59. > Is there any way in Ada to iterate abstractly over the contents of a 
  60. > container,...
  61.  
  62. Several ways:
  63.  
  64.     - Write a generic procedure Iterate, which takes a formal
  65.       procedure representing the body of the loop -- that is,
  66.       the formal procedure says what to do for each element.
  67.  
  68.     - Write a procedure that takes an access-to-procedure as
  69.       a parameter.  In standard Ada, this only works if the
  70.       procedure being passed in is non-nested, which makes this
  71.       technique fairly useless.  In GNAT, you can "cheat", by
  72.       using 'Unrestricted_Access, but that's not standard Ada.
  73.  
  74.     - Write an Iterator class.  Define any particular loop
  75.       by deriving from that, and overriding the Do_One_Element
  76.       method, or whatever.  I think there's an example in the
  77.       Rationale.
  78.  
  79.     - For each data structure, define Start, Done, Current_Element,
  80.       and Get_Next operations.  Or some variation on this.
  81.  
  82. None of these is as pretty as the Sather solution, but they achieve the
  83. main goal, which is to have the module that defines the data structure
  84. define how to loop, and the clients define what they do at each
  85. iteration.
  86.  
  87. >... i.e. without writing each loop in a way which depends
  88. > strongly on the implementation of the container?  I know I 
  89. > could define a container class Foo_Basket_Type which would 
  90. > let me do something like
  91. >     for I = 1 .. Size(Foo_Basket) loop -- class implemented as array
  92. >        Sum := Sum + Bletchery(Element(Foo_Basket, I));
  93. >     end loop;
  94. > or 
  95. >     I : Foo_Basket_Iterator_Type := Head(Foo_Basket);
  96. >     ..
  97. >     while not Is_Done(I) loop -- class implemented as list
  98. >        Sum := Sum + Bletchery(dereference I);
  99. >        I := Next(I);
  100. >     end loop;
  101.  
  102. It seems like the above does not have to imply "class implemented as
  103. list".  So just write all your loops like that, whether the
  104. implementation is a list, or an array, or whatever.  You can do this in
  105. most languages.  This is what I was suggesting in the fourth item above.
  106.  
  107. > but what I'd really like to is something like 
  108. >     for each I in Foo_Basket loop -- don't much care how class is implemented
  109. >        Sum := Sum + Bletchery(dereference I);
  110. >     end loop;
  111. > I understand that in languages like Sather, I could do this without
  112. > macros.  In G++ I can come pretty close to this with CPP macros:
  113. >     FOR_EACH(i, foo_basket)
  114. >       sum += bletchery(*i);
  115. > In standard C++ (without the G++ `typeof' operator) I'd write something like
  116. >     FOR_EACH(i, Foo_Basket::Iterator, foo_basket)
  117. >       sum += bletchery(*i);
  118. > I use this idiom a lot -- about once per 40 lines of code in my
  119. > current project.  I much prefer it to the alternative of making my
  120. > code depend on the implementation of the container.
  121.  
  122. I don't agree that the only alternative to macros is to break the
  123. abstraction.  The techniques I mentioned above also achieve your goal,
  124. although they are admittedly somewhat ugly.  Macros can add syntactic
  125. sugar to those techniques, but don't fundamentally change things.
  126.  
  127. >...Is there any way of
  128. > doing something like this in Ada?  (I imagine there is, since the
  129. > alternatives look unnecessarily difficult to maintain.)
  130.  
  131. I'll note that the alternatives I gave could be done in C++, too,
  132. without macros.
  133.  
  134. > Due in part to my problems with GDB mentioned above, my C++ programs
  135. > tend to contain a lot of calls to macros MUTTER1, MUTTER2,
  136. > etc. defined either as no-op (for low levels of verbosity) or as
  137. >    #define MUTTER1(x) do { cerr << mutter_prefix << x << '\n'; } while (false)
  138. > so that I can write things like 
  139. >    MUTTER1("done with sampling, w = " << w << ", table = " << table);
  140. > concisely.  It's my impression that Ada's I/O facilities make it hard
  141. > to do trivial things like this concisely.  Is this wrong?  I don't really
  142. > want to have to write 
  143. >    if (Global_Verbosity >= 1) then
  144. >      Write_Mutter_Indent(Global_Mutter);
  145. >      Write(Global_Mutter, "done with sampling, W = ");
  146. >      Write(Global_Mutter, W);
  147. >      Write(Global_Mutter, ", table = ");
  148. >      Write(Global_Mutter, Table);
  149. >      Write_Line(Global_Error); -- silly typo encouraged by excess verbosity
  150. >    end if;
  151. > for a simple statement like the one above.
  152.  
  153. The usual thing is to write something like:
  154.  
  155.     Put_Line("done with sampling, W = " & Image(W)
  156.            & ", table = " & Image(Table));
  157.  
  158. For simple data types, there is the 'Image attribute.  For others, you
  159. have to write your own Image function, which converts it to a string.
  160. You said you wanted to do that anyway.  If you don't like
  161. Text_IO.Put_Line, write your own: Two procedures for each verbosity
  162. level, and one of those two can add the new-line.  Or maybe you always
  163. want a new-line.  Or maybe the verbosity should be passed as a
  164. parameter, with a default.  I can imagine many variations.
  165.  
  166. Some people go even further, and define overloaded versions of "&" that
  167. do both the concatenation and the conversion-to-string.  Seems like
  168. overkill to me, but some people like it.
  169.  
  170. > When I make two different instantiations of a generic package with the
  171. > same arguments, I understand the compiler treats them formally as two
  172. > different packages, which is OK with me.  However, I'd appreciate
  173. > knowing the compiler wouldn't actually output two redundant copies of
  174. > the corresponding (identical?) machine code, but instead share the
  175. > code.  I saw somewhere that the compiler is given considerable freedom
  176. > to share one instantiation between several arguments if it thinks it's
  177. > appropriate, which is also OK with me.  However, I haven't seen any
  178. > guarantee that the compiler won't output redundant copies for
  179. > instantiations with identical arguments.  Is there such a guarantee?
  180.  
  181. No.  Some compilers do it, some don't.  Currently, GNAT does not.
  182.  
  183. If you want to avoid code bloat, you can usually arrange for *most* of
  184. the code in a generic to be separated out into a non-generic package.
  185. Sometimes, this requires low-level hacks, but the low-level hacks are
  186. hidden inside the generic and its helper package, so they need not
  187. concern clients.
  188.  
  189. > My examples of `for each' and `mutter' above share a common feature:
  190. > I'd like to abstract away a common pattern so that I only need to type
  191. > each argument once, and I haven't figured out how to do it in Ada.
  192.  
  193. Macros can be used to achieve that, but in many cases, so can
  194. procedures, generics, Sather's iterators, etc.  IMHO, the more
  195. restricted features are generally better than macros.  Macros are more
  196. powerful, but also more difficult to understand.  TeX is a language that
  197. uses macros for just about everything, and I find TeX code to be totally
  198. incomprehensible, despite the fact that I've read the TeX Book 4 times.
  199.  
  200. >...I
  201. > don't object to the rest of the verbosity I have seen in Ada: I can
  202. > see that it might make programs more readable, and since it's checked
  203. > by the compiler it shouldn't make programs significantly harder to
  204. > maintain.  However, the kind of verbosity required to hand-code
  205. > patterns like `for each' and `mutter' does not seem to make code more
  206. > readable, and since it is not checked by the compiler I'm afraid it
  207. > might cause maintenance problems by making it possible to add bugs by
  208. > changing some but not all occurrences of the redundant terms.  Are
  209. > there ways (e.g.  in the cases described above, or other cases that I
  210. > haven't thought of yet) in which Ada will force me to do this kind of
  211. > thing where C++ wouldn't?  If so, is this a bad thing (as I suspect),
  212. > or is it a positive feature in some sense that I haven't figured out,
  213. > or is it just the price we pay for the benefit of being guaranteed
  214. > that no one has abused macros in the program?
  215.  
  216. I think the last phrase ("price we pay...") is accurate.  I actually
  217. think macros would be nice to have in some rare cases.  But in *most*
  218. cases, if you're using macros, that's an indication of a language flaw
  219. -- you didn't have a higher-level feature that got the job done, so you
  220. had to resort to macros.
  221.  
  222. You'll find a lot of anti-macro fanatics in the Ada world.
  223.  
  224. > Why doesn't Ada 95 allow declarations to be interspersed with ordinary
  225. > statements as C++ does?  (Or does it?  _Ada as a Second Language_ is a
  226. > big book!)  It seems to me that the C++ approach is a small but
  227. > definite win.  Does it interact very badly somehow with all those
  228. > guarantees on elaboration order?
  229.  
  230. To intersperse declarations, you have to use a block_statement, like
  231. this:
  232.  
  233.     for I in Some_String'Range loop -- I wish I could easily use an iterator here ;-)
  234.         declare
  235.             X: constant Character := Some_String(I);
  236.         begin
  237.             ...
  238.         end;
  239.     end loop;
  240.  
  241. To me, the "declare", "begin", and "end" are just useless verbosity.
  242. I prefer the C++ rule.
  243.  
  244. As to WHY the Ada syntax is this way, I'm not sure.  It's partly because
  245. it was inherited from Pascal.  In Pascal, "begin" separates purely
  246. compile-time declarative stuff from purely run-time algorithmic stuff,
  247. so the "begin" makes some conceptual sense.  But in Ada, the
  248. declarations can do all kinds of run-time stuff, so putting "begin" in
  249. between declarations and statements makes less sense.  Pascal doesn't
  250. have block_statements, but the syntax of Ada's block_statements comes
  251. from the same Pascal heritage.
  252.  
  253. The "begin" also makes a difference for exception handling and tasking.
  254. But I don't find these reasons compelling, either.
  255.  
  256. > Someone remarked -- in this newsgroup recently IIRC -- that macros
  257. > were explicitly disallowed in the design goals for Ada (Ada 83?),
  258. > since they make programs hard to understand.  I don't remember the
  259. > exact wording, but as I remember the key reason was that you would
  260. > never know what was a macro and what wasn't without reading the entire
  261. > program hunting for macro definitions.  (I searched for `macro' in the
  262. > Rationale without success, so I'm just going on speculation and dim
  263. > memory here.)  It seems to me that that is a funny objection: most
  264. > macro processors these days don't require a characteristic pattern to
  265. > introduce macro expansions, but as far as I can tell there's no reason
  266. > that you couldn't restrict macro expansion to e.g. patterns preceded
  267. > by the keyword `macro'.
  268.  
  269. I don't think this is the main reason people think macros are hard to
  270. understand.  As you say, it would be easy to design the syntax so that a
  271. macro invokation looks different from anything else.
  272.  
  273. Macros are generally hard to understand for other reasons, I think.
  274. Part of the problem is the low-level character-based nature of macros.
  275. But as you point out below, that's not true of all known macro
  276. facilities.  Part of the problem is the lack of scoping rules -- if a
  277. macro expansion refers to a global variable X, it's referring to
  278. whatever X happens to be lying around at the point of the macro
  279. expansion.  Contrast that with Ada's generics, where the names are bound
  280. at the site of the generic itself.  Part of the problem is that you have
  281. to imagine what the macro expands to in order to understand what it
  282. does, and complex code trasformations are hard to imagine accurately.
  283. TeX macros have additional problems, like the fact that you can't tell
  284. at the call site how many arguments are being passed -- in fact, you
  285. can't in general tell until run time.
  286.  
  287. >...  Granted, C's macro facilities are fairly
  288. > disgusting and inconsistent with the design goals of Ada, but it seems
  289. > to me a macro facility (or `generic syntax' facility?) more consistent
  290. > with Ada could be useful -- perhaps something closer to Scheme's
  291. > `hygienic macros' than to C's macro preprocessor.  Some restrictions
  292. > (e.g. only allowing macros to expand into expressions, sequences of
  293. > statements, or sequences of declarations, and not into arbitrary textual
  294. > strings) and perhaps importing from Lisp the idea that macros are
  295. > transformations on patterns of language tokens and expressions, rather
  296. > than transformations on patterns of characters) could do a pretty
  297. > decent job of discouraging people from writing truly screwy macros
  298.  
  299. I agree.  Lisp macros are much less painful than character-level macros.
  300.  
  301. > without forbidding useful macros like `For_Each' or (to generalize
  302. > `MUTTER') `Write_Sequence' (sending a bunch of items to the same
  303. > stream, and using the language's overloading facility to sort out
  304. > which version of the Write procedure to call for each).
  305.  
  306. If you complain that you want macros to do For_Each, I'll answer by
  307. giving you iterators, not by giving you macros.  Same for Write_Sequence
  308. -- better to use a procedure call than a macro call, IMHO.
  309.  
  310. >...Would this
  311. > have been a good idea, except perhaps that the language is too
  312. > complicated already, or would this be a bad idea for some more
  313. > fundamental reason?
  314.  
  315. I think most Ada people would say that macros inherently cause
  316. hard-to-understand code, and therefore should be abolished.  I don't
  317. agree.  I would like to have a macro facility (at a higher level than
  318. character-level), but I would use it rarely.
  319.  
  320. > Finally, I found it intriguing when someone (somewhere in the endless
  321. > C++ vs. Ada thread) described a program which used exceptions to
  322. > convert runtime errors to `graceful degradation' so successfully that
  323. > the program (for fire control?!) continued operating more-or-less
  324. > correctly despite numerous bugs. ...
  325.  
  326. I'm not impressed by that example.  It's true that exceptions can be
  327. useful in designing a fault-tolerant system, but fault-tolerance is
  328. still very hard, and needs to be very carefully designed.  For *most*
  329. programs, the primary purpose of exceptions, most of the time, is to
  330. detect bugs as early as possible, and the response is to fix the bug,
  331. not to allow the program to muddle along in a confused state.
  332.  
  333. - Bob
  334.  
  335. P.S. I hope you enjoy Ada.  Why not get a copy of GNAT, and try it out?
  336.